#include "stdlib.h"
#include "string.h"
#include <math.h>
#include "dvc.h"
#include "dvc_cmd_frame.h"
#include "dvc_log.h"

#define DVC_DEBUG 1

#if DVC_DEBUG
#include "stdio.h"
#define log_write printf
#else
#define log_write(x)
#endif

void dvc_init(dvc_t dvc, dvc_ops_t *ops, dvc_user_cfg_t *cfg)
{
    if (!dvc || !ops)
        return;
    memset(dvc, 0, sizeof(dvc_s));
    dvc->push_interval = 1000;
    dvc->ops = ops;
    dvc->retry_count = 3;
    dvc->last_day = ops->get_time ? ops->get_time() / 86400 : 0;
#if defined(DVC_ENABLE_LOG) || defined(DVC_ENABLE_EVENT_LOG)
    if (ops->get_logs)
        ops->get_logs(dvc);
#endif
    /* 获取用户/默认配置 */
    if (!cfg)
        dvc_read_user_config(dvc);
    else
        dvc->user_cfg = *cfg;
    /* 写入配置到AFE芯片 */
    dvc_config_init_default(dvc);
    /* 给默认值 */
    dvc->coulomb_counter.bat_rmA = dvc->coulomb_counter.bat_mA;
    /* 从flash中加载对应的历史值 */
    dvc_hitstory_restore(dvc);
}

dvc_t dvc_create(dvc_ops_t *ops, dvc_user_cfg_t *cfg)
{
    if (!ops)
    {
        log_write("Invalid parameter\n");
        return NULL;
    }
    dvc_t dvc = malloc(sizeof(dvc_s));
    if (!dvc)
    {
        log_write("Failed to malloc dvc object\n");
        return dvc;
    }
    dvc_init(dvc, ops, cfg);
    return dvc;
}

uint8_t dvc_reset(dvc_t dvc)
{
    if (!dvc || !dvc->ops || !dvc->ops->wakup)
        return 1;
    uint8_t data = 0xFF;
    dvc_frame_write(dvc, dvc_cmd_sleep, &data, 1);
    if (dvc->ops->delay_ms)
        dvc->ops->delay_ms(50);

    dvc->ops->wakup(dvc->ops->user_data);

    if (dvc->ops->delay_ms)
        dvc->ops->delay_ms(50);

#ifdef DVC_ENABLE_EVENT_LOG
    dvc_log_event_t event_log = {
        .timestamp = dvc->tick,
        .event = DVC_EVENT_TYPE_RESET,
        .flag = DVC_EVENT_FLAG_USER,
        .state = 0,
    };
    dvc_log_event_push(dvc, &event_log);
#endif
    dvc_read_user_config(dvc);

    return dvc_config_init_default(dvc);
}

void dvc_alert(dvc_t dvc)
{
    if (dvc)
    {
        dvc->alert = 1;
        dvc->io_alert = 1;
    }
}

void dvc_chg(dvc_t dvc, uint8_t en)
{
    if (!dvc)
        return;
    dvc->w_cfg.cfg0.chg_en = en > 0;

#ifdef DVC_ENABLE_EVENT_LOG
    // 如果chg_en状态发生变化，记录事件日志
    if (dvc->w_cfg.cfg0.chg_en != dvc->cfg.cfg0.chg_en)
    {
        dvc_log_event_t event_log = {
            .timestamp = dvc->tick,
            .event = DVC_EVENT_TYPE_CHG,
            .flag = DVC_EVENT_FLAG_USER,
            .state = dvc->w_cfg.cfg0.chg_en,
        };
        // 将事件日志推入日志队列
        dvc_log_event_push(dvc, &event_log);
    }
#endif
}

void dvc_dsg(dvc_t dvc, uint8_t en)
{
    if (!dvc)
        return;
    dvc->w_cfg.cfg0.dsg_en = en > 0;

#ifdef DVC_ENABLE_EVENT_LOG
    // 如果dsg_en状态发生变化，记录事件日志
    if (dvc->w_cfg.cfg0.dsg_en != dvc->cfg.cfg0.dsg_en)
    {
        dvc_log_event_t event_log = {
            .timestamp = dvc->tick,
            .event = DVC_EVENT_TYPE_DSG,
            .flag = DVC_EVENT_FLAG_USER,
            .state = dvc->w_cfg.cfg0.dsg_en,
        };
        // 将事件日志推入日志队列
        dvc_log_event_push(dvc, &event_log);
    }
#endif
}

void dvc_aes(dvc_t dvc, uint8_t en, uint8_t flag)
{
    if (!dvc)
        return;
    dvc->aes = en > 0;
    dvc->push = 1;
    dvc->push_tick += dvc->push_interval;
    dvc->aes_tick = dvc->tick;
    if (flag == DVC_EVENT_FLAG_USER)
        dvc->aes_user = en;
    if (dvc->ops->set_aes)
        dvc->ops->set_aes(dvc->ops->user_data, dvc->aes);
#ifdef DVC_ENABLE_EVENT_LOG
    dvc_log_event_t event_log = {
        .timestamp = dvc->tick,
        .event = DVC_EVENT_TYPE_AE,
        .flag = flag ? DVC_EVENT_FLAG_USER : DVC_EVENT_FLAG_AFE,
        .state = en,
    };
    dvc_log_event_push(dvc, &event_log);
#endif
}

/* 校准 */
void dvc_calib(dvc_t dvc, float v, float c)
{
    if (!dvc)
        return;
    dvc->calib.voltage = v;
    dvc->calib.current = c;
}

void dvc_tick(dvc_t dvc, uint16_t tick)
{
    if (!dvc)
        return;
    dvc->tick += tick;
    dvc->push_tick += tick;
    if (dvc->tick % 256 < tick)
        dvc->tick_flag |= dvc_tick_flag_256ms;
    if (dvc->tick % 1000 < tick)
        dvc->tick_flag |= dvc_tick_flag_1s;
    if (dvc->tick % 2000 < tick)
        dvc->tick_flag |= dvc_tick_flag_2s;
    if (dvc->tick % 4000 < tick)
        dvc->tick_flag |= dvc_tick_flag_4s;
    if (dvc->tick % 8000 < tick)
        dvc->tick_flag |= dvc_tick_flag_8s;
    if (dvc->tick % 16000 < tick)
        dvc->tick_flag |= dvc_tick_flag_16s;
    if (dvc->tick % 32000 < tick)
        dvc->tick_flag |= dvc_tick_flag_32s;
    if (dvc->tick % 64000 < tick)
        dvc->tick_flag |= dvc_tick_flag_64s;
}

void dvc_monitor(dvc_t dvc)
{
    if (!dvc)
        return;

    uint8_t tf = dvc->tick_flag;

    if (tf & dvc_tick_flag_256ms)
    {
        dvc->tick_flag &= ~dvc_tick_flag_256ms;
        dvc->read_cv = 1;
        dvc->read_c = 1;
        dvc->read_bat = 1;
        dvc->read_temp = 1;

        uint8_t cfg0_b1 = 0;
        memcpy(&cfg0_b1, ((uint8_t *)&dvc->cfg.cfg0) + 1, 1);

        /* 开启任一节电池均衡会使VADC自动进入间断测量模式，默认轮询周期为 2s。 */
        if (dvc->cfg.cfg0.vs_pt == dvc_cs_vs_pt_continuous && !(cfg0_b1 & 0x3F))
        {
            dvc->read_bat = 1;
            dvc->read_temp = 1;
        }
    }
    if (tf & dvc_tick_flag_1s)
    {
        dvc->tick_flag &= ~dvc_tick_flag_1s;
        dvc->check_reg = 1;

        uint8_t cfg0_b1 = 0;
        memcpy(&cfg0_b1, ((uint8_t *)&dvc->cfg.cfg0) + 1, 1);

        /* 开启任一节电池均衡会使VADC自动进入间断测量模式，默认轮询周期为 2s。 */
        if (dvc->cfg.cfg0.vs_pt == dvc_cs_vs_pt_1s && !(cfg0_b1 & 0x3F))
        {
            dvc->read_bat = 1;
            dvc->read_temp = 1;
        }
    }
    if (tf & dvc_tick_flag_2s)
    {
        dvc->tick_flag &= ~dvc_tick_flag_2s;

        uint8_t cfg0_b1 = 0;
        memcpy(&cfg0_b1, ((uint8_t *)&dvc->cfg.cfg0) + 1, 1);

        if (dvc->cfg.cfg0.vs_pt == dvc_cs_vs_pt_2s || ((dvc->cfg.cfg0.vs_pt == dvc_cs_vs_pt_1s || dvc->cfg.cfg0.vs_pt == dvc_cs_vs_pt_continuous) && (cfg0_b1 & 0x3F)))
        {
            dvc->read_bat = 1;
            dvc->read_temp = 1;
        }
    }
    if (tf & dvc_tick_flag_4s)
    {
        dvc->tick_flag &= ~dvc_tick_flag_4s;
        if (dvc->cfg.cfg0.vs_pt == dvc_cs_vs_pt_4s)
        {
            dvc->read_bat = 1;
            dvc->read_temp = 1;
        }
    }
    if (tf & dvc_tick_flag_8s)
    {
        dvc->tick_flag &= ~dvc_tick_flag_8s;
        if (dvc->cfg.cfg0.vs_pt == dvc_cs_vs_pt_8s)
        {
            dvc->read_bat = 1;
            dvc->read_temp = 1;
        }
    }
    if (tf & dvc_tick_flag_16s)
    {
        dvc->tick_flag &= ~dvc_tick_flag_16s;
        if (dvc->cfg.cfg0.vs_pt == dvc_cs_vs_pt_16s)
        {
            dvc->read_bat = 1;
            dvc->read_temp = 1;
        }
    }
    if (tf & dvc_tick_flag_32s)
    {
        dvc->tick_flag &= ~dvc_tick_flag_32s;
        if (dvc->cfg.cfg0.vs_pt == dvc_cs_vs_pt_32s)
        {
            dvc->read_bat = 1;
            dvc->read_temp = 1;
        }
    }
    if (tf & dvc_tick_flag_64s)
    {
        dvc->tick_flag &= ~dvc_tick_flag_64s;
        if (dvc->cfg.cfg0.vs_pt == dvc_cs_vs_pt_64s)
        {
            dvc->read_bat = 1;
            dvc->read_temp = 1;
        }
    }

#ifdef DVC_ENABLE_EVENT_LOG
    if (dvc->io_alert)
    {
        dvc->io_alert = 0;
        dvc_log_event_t event_log = {
            .timestamp = dvc->tick,
            .event = DVC_EVENT_TYPE_IO_ALTER,
            .flag = DVC_EVENT_FLAG_AFE,
            .state = 1,
        };
        dvc_log_event_push(dvc, &event_log);
    }
#endif

    if (dvc->alert)
    {
        /* 刷新标志位 */
        dvc_get_status_current_voltage(dvc);

        if (dvc->status.status0.ov) /* 过压 */
        {
            if (dvc->tick >= dvc->ov_tick)
            {
                uint32_t max = (dvc->user_cfg.afe.covt + 546) * 586 / 100; /* 0.586V/LSB */
                uint8_t clear = 1;
                for (uint8_t i = 0; i < dvc->bat_num; i++)
                {
                    if (dvc->bat_vol[i] > max)
                    {
                        clear = 0;
                        break;
                    }
                }
                if (clear)
                    dvc->status.status0.ov = 0;
            }
        }

        if (dvc->status.status0.uv) /* 欠压 */
        {
            if (dvc->tick >= dvc->uv_tick)
            {
                uint32_t min = (dvc->user_cfg.afe.cuvt + 324) * 586 / 100; /* 0.586V/LSB */
                uint8_t clear = 1;
                for (uint8_t i = 0; i < dvc->bat_num; i++)
                {
                    if (dvc->bat_vol[i] < min)
                    {
                        clear = 0;
                        break;
                    }
                }
                if (clear)
                    dvc->status.status0.uv = 0;
            }
        }

        if (dvc->status.status0.ocd || dvc->status.status0.occ) /* 充放电过流 */
        {
            if (dvc->tick >= dvc->ccd_tick)
            {
                dvc->status.status0.ocd = 0;
                dvc->status.status0.occ = 0;
            }
        }

        if (dvc->status.status0.scd) /* 放电短路 */
        {
            if (dvc->tick >= dvc->scd_tick)
                dvc->status.status0.scd = 0;
        }

        uint8_t clear = 1;
        dvc_reg_status0_t status = dvc->status.status0;
        if (status.ocd || status.scd || status.uv || status.ov || status.occ || status.cs_st || status.vs_st) /* 警报还在 */
            clear = 0;

        /* 待做事项:
            1. 每次触发警报时，记录时间, 等待用户处理 / 用户超时不处理则自动恢复
         */
        if (clear) /* 警报已清除 */
        {
            dvc_clear_alert(dvc, DVC_EVENT_FLAG_AFE);
            dvc->alert = 0;
            printf("清除警报\r\n");
        }
    }

    if (dvc->check_reg)
    {
        dvc->check_reg = 0;
        if (dvc_config_check(dvc))
            dvc_config_commit(dvc);
    }

    if (dvc->read_bat)
    {
        dvc->read_bat = 0;
        if (dvc_get_bat_voltage(dvc))
            dvc->read_bat = 1;
    }

    if (dvc->read_cv)
    {
        dvc->read_cv = 0;
        if (dvc_get_status_current_voltage(dvc)) /* 读取失败则下次循环重试 */
            dvc->read_cv = 1;
    }

    if (dvc->read_temp)
    {
        dvc->read_temp = 0;
        if (dvc_get_temp(dvc))
            dvc->read_temp = 1;
    }

    if (dvc->read_c) /* 256ms执行一次 */
    {
        dvc->read_c = 0;
        dvc->coulomb_count++;            /* 计数器+1 */
        float mA = dvc->current * 0.256; /* 累计256ms内电流使用 */
        float mW = dvc->power * 0.256;

        /* 1秒内累加 */
        dvc->coulomb_counter.sec.mA += mA;  /* 电流累计 */
        dvc->coulomb_counter.sec.mW += mW;  /* 功率累计 */
        dvc->coulomb_counter.bat_rmA += mA; /* 电池容量累计 */
        if (dvc->coulomb_counter.bat_rmA < 0.001f)
            dvc->coulomb_counter.bat_rmA = 0;

        /* 库仑计累计 和 剩余时间计算 */
        float current = fabsf(dvc->current);
        if (dvc->current > 0.0f) /* 充电 */
        {
            /* 总累加 */
            dvc->coulomb_counter.sum.mA += mA;
            dvc->coulomb_counter.sum.mW += mW;
            /* 今日充电累计 */
            dvc->coulomb_counter.chg.mA += mA;
            dvc->coulomb_counter.chg.mW += mW;
            if (dvc->coulomb_counter.bat_mA >= 0.0)
            {
                if (current > 1e-6f)
                    dvc->coulomb_counter.bat_rtime = (dvc->coulomb_counter.bat_mA - dvc->coulomb_counter.bat_rmA) / current;
                else
                    dvc->coulomb_counter.bat_rtime = 0xFFFFFFFF;
            }
        }
        else /* 放电 */
        {
            dvc->coulomb_counter.dsg.mA += mA;
            dvc->coulomb_counter.dsg.mW += mW;
            if (current > 1e-6f)
                dvc->coulomb_counter.bat_rtime = dvc->coulomb_counter.bat_rmA / current;
            else
                dvc->coulomb_counter.bat_rtime = 0xFFFFFFFF;
        }

        /* 每秒清算一次*/
        if (dvc->coulomb_count == 4)
        {
            dvc->coulomb_count = 0;
#ifdef DVC_ENABLE_LOG
            dvc_log_record_sec(dvc, &dvc->log.sec[dvc->sec_tick % 60]);
            dvc->sec_tick++;
            if (dvc->sec_tick % 60 == 0) /* 1min */
            {
                dvc_log_record_minc(dvc, &dvc->log.min[(dvc->sec_tick / 60) % 60]);
                if (dvc->sec_tick % 3600 == 0) /* 1hour */
                    dvc_log_record_hour(dvc, &dvc->log.hour[(dvc->sec_tick / 3600) % 24]);
            }
#endif
            dvc->coulomb_counter.sec.mA = 0;
            dvc->coulomb_counter.sec.mW = 0;

            uint32_t timestamp = dvc->tick;
            if (dvc->ops && dvc->ops->get_time)
                timestamp = dvc->ops->get_time();
            uint32_t day = timestamp / 86400;
            if (day - dvc->last_day > 1) /* NTP时间同步导致的日期变更 */
            {
                log_write("last:%ld cur:%ld timestamp:%lu only sync\r\n", dvc->last_day, day, timestamp);
                dvc->last_day = day;
            }

            if (day != dvc->last_day) /* 每日清零 */
            {
                dvc->last_day = day;
                dvc->coulomb_counter.chg.mA = 0;
                dvc->coulomb_counter.chg.mW = 0;
                dvc->coulomb_counter.dsg.mA = 0;
                dvc->coulomb_counter.dsg.mW = 0;
#ifdef DVC_ENABLE_LOG
                dvc_log_t log = {0};
                dvc_log_record(dvc, DVC_LOG_PUSH_TYPE_YEARS, &log, 2);
                dvc_log_record_years(dvc, &log);
                if (dvc->ops->save_log)
                    dvc->ops->save_log((uint8_t *)&log, 0);
                dvc->sec_tick = 0;
#endif
                if (dvc->coulomb_counter.bat_mA > 0)
                {
                    uint16_t cycle_count = 0;
                    cycle_count = dvc->coulomb_counter.sum.mA / dvc->coulomb_counter.bat_mA;

                    // 衰减系数
                    static const float decay_coefficient[BAT_TYPE_UNKNOWN + 1] = {0.05f, 0.1f, 0.07f, 0.025f, 0.025f};
                    float k = decay_coefficient[BAT_TYPE_UNKNOWN];

                    // 指数模型计算容量剩余百分比
                    dvc->coulomb_counter.bat_health = expf(-k * cycle_count);
                }
            }
        }
        dvc->c_tick = dvc->tick;
    }

    /*总线电流电压有变化 */
    if (dvc->change & dvc_data_current_change)
    {
        dvc->change &= ~dvc_data_current_change;
        dvc->push = 1;
    }
    /* 电池电压有变化 */
    if (dvc->change & dvc_data_voltage_change)
    {
        dvc->change &= ~dvc_data_voltage_change;
        dvc->push = 1;
    }
    /* 内外部温度有变化 */
    if (dvc->change & dvc_data_temp_change)
    {
        dvc->change &= ~dvc_data_temp_change;
        dvc->push = 1;
    }

    if (dvc->push) /* 数据已刷新 */
    {
        /* 到了数据上报时间 */
        if (dvc->push_tick >= dvc->push_interval)
        {
            dvc->push = 0;
            dvc->push_tick %= dvc->push_interval;
            /* 数据上报 */
            if (dvc->ops && dvc->ops->new_data)
                dvc->ops->new_data(dvc);
        }
    }
}